package com.gf.common.lucene.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.paoding.analysis.analyzer.PaodingAnalyzer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.gf.base.type.IndexType;
import com.gf.common.bean.Page;
import com.gf.common.constant.IndexExam;
import com.gf.common.constant.IndexPerson;
import com.gf.common.lucene.service.LuceneService;
import com.gf.exam.model.Exam;
import com.gf.user.model.User;

@Service("luceneService")
public class LuceneServiceImpl implements LuceneService {

	Log log = LogFactory.getLog(LuceneServiceImpl.class);

	// 每增加100次进行优化
	private int i = 1;

	private IndexWriter indexWriter;

	private Analyzer analyzer;

	@Value("${lucene.index.dir}")
	private String diskDir;

	/**
	 * create:false
	 */
	@Override
	public <T> void add(IndexType indexType, List<T> obj) {
		try {
			FSDirectory dir = FSDirectory.open(new File(diskDir));
			analyzer = new PaodingAnalyzer();
			indexWriter = new IndexWriter(dir, analyzer, false,
					MaxFieldLength.UNLIMITED);

			// exam更新
			if (indexType.toString().equals(IndexType.EXAM.toString())) {
				for (T t : obj) {
					Document doc = new Document();
					Exam exam = (Exam) t;

					Field field = new Field(IndexExam.ID, "" + exam.getId(),
							Store.YES, Index.NO);
					doc.add(field);
					// 不用存储，当要建立索引
					field = new Field(IndexExam.INTRODUCTION,
							exam.getIntroduction(), Store.NO, Index.ANALYZED);
					doc.add(field);
					// 不用存储，当要建立索引
					field = new Field(IndexExam.TITLE, exam.getTitle(),
							Store.NO, Index.ANALYZED);
					doc.add(field);
					// 不用建立 直接存储
					field = new Field(IndexExam.USERID, "" + exam.getUserId(),
							Store.YES, Index.NO);
					doc.add(field);
					// 建立索引，根据用户搜索
					field = new Field(IndexExam.USERNAME, exam.getUserName(),
							Store.NO, Index.ANALYZED);
					doc.add(field);
					// 不用建立索引
					field = new Field(IndexType.EXAM.toString(),
							IndexType.EXAM.toString(), Store.YES, Index.NO);
					doc.add(field);
					indexWriter.addDocument(doc);
				}
			}
			// user
			else {
				for (T t : obj) {
					Document doc = new Document();
					User user = (User) t;

					Field field = new Field(IndexPerson.ID, "" + user.getId(),
							Store.YES, Index.NO);
					doc.add(field);
					// 不用存储，要建立索引
					field = new Field(IndexPerson.EMAIL, user.getEmail(),
							Store.NO, Index.ANALYZED);
					doc.add(field);
					// 不用存储，要建立索引
					field = new Field(IndexPerson.NICKNAME, user.getNickname(),
							Store.NO, Index.ANALYZED);
					doc.add(field);

					field = new Field(IndexPerson.REALNAME, user.getRealName(),
							Store.NO, Index.ANALYZED);
					doc.add(field);

					// 不用建立索引
					field = new Field(IndexType.USER.toString(),
							IndexType.USER.toString(), Store.YES, Index.NO);
					doc.add(field);
					indexWriter.addDocument(doc);
				}

			}
			// 每更新100次优化一次
			if (i % 100 == 0) {
				indexWriter.optimize();
				i = 1;
			}
			indexWriter.commit();
			indexWriter.close();
		} catch (Exception e) {
			log.warn("同步出错 ");
		}
	}

	/**
	 * create:true;
	 */
	@Override
	public <T> void rebuild(List<T>... lists) {

		try {
			FSDirectory dir = FSDirectory.open(new File(diskDir));
			analyzer = new PaodingAnalyzer();
			indexWriter = new IndexWriter(dir, analyzer, false,
					MaxFieldLength.UNLIMITED);
			// 删除老的索引
			indexWriter.deleteAll();

			// 根据类型 重新建索引
			for (int i = 0; i < lists.length; i++) {
				List<T> list = lists[i];
				if (list == null || list.size() == 0) {
					continue;
				}

				if (list.get(0) instanceof User) {
					add(IndexType.USER, list);
				} else if (list.get(0) instanceof Exam) {
					add(IndexType.EXAM, list);
				}
			}

		} catch (Exception e) {
			log.warn("rebuild() 出错");
		}

	}

	/**
	 * 多字段搜索,按ID从小到大返回
	 */
	@Override
	public List<String> search(IndexType indexType, String keyword, Page page) {
		try {
			Query query = null;
			analyzer = new PaodingAnalyzer();
			IndexSearcher searcher = new IndexSearcher(
					FSDirectory.open(new File(diskDir)));

			// 测试项目
			if (indexType.toString().equals(IndexType.EXAM.toString())) {
				// 要搜索的字段
				String fields[] = { IndexExam.INTRODUCTION, IndexExam.TITLE,
						IndexExam.USERNAME };
				// 与搜索的字段相对应
				BooleanClause.Occur[] flags = new BooleanClause.Occur[] {
						BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD,
						BooleanClause.Occur.SHOULD };
				query = MultiFieldQueryParser.parse(Version.LUCENE_30, keyword,
						fields, flags, analyzer);
				// 根据ID对搜索结果进行排序,false升序
				Sort sort = new Sort(new SortField(IndexExam.ID,
						SortField.LONG, false));
				// 最多返回前10000条记录
				TopDocs hit = searcher.search(query, null, 10000, sort);
				// 总的命中数
				int totalHit = hit.totalHits;
				// 总的结果集
				ScoreDoc[] scoreDocs = hit.scoreDocs;

				page.setTotal(totalHit);
				int beginIndex = page.getStartIndex();
				int endIndex = Math.min(beginIndex + page.getPageSize(),
						scoreDocs.length);
				// 返回
				List<String> ids = new ArrayList<String>();
				for (int i = beginIndex; i < endIndex; i++) {
					int docIndex = scoreDocs[i].doc;
					Document doc = searcher.doc(docIndex);
					ids.add(doc.get(IndexExam.ID));
				}
				return ids;
			}
			// 用户
			else if (indexType.toString().equals(IndexType.USER.toString())) {
				String fields[] = { IndexPerson.NICKNAME, IndexPerson.EMAIL };
				BooleanClause.Occur[] occurs = new BooleanClause.Occur[] {
						BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };
				query = MultiFieldQueryParser.parse(Version.LUCENE_30, keyword,
						fields, occurs, analyzer);
				// 根据ID对搜索结果进行排序,false升序
				Sort sort = new Sort(new SortField(IndexPerson.ID,
						SortField.LONG, false));
				// 最多返回前1000条记录
				TopDocs hit = searcher.search(query, null, 10000, sort);
				// 总的命中数
				int totalHit = hit.totalHits;
				// 总的结果集
				ScoreDoc[] scoreDocs = hit.scoreDocs;

				page.setTotal(totalHit);
				int beginIndex = page.getStartIndex();
				int endIndex = Math.min(beginIndex + page.getPageSize(),
						scoreDocs.length);
				// 返回
				List<String> ids = new ArrayList<String>();
				for (int i = beginIndex; i < endIndex; i++) {
					int docIndex = scoreDocs[i].doc;
					Document doc = searcher.doc(docIndex);
					ids.add(doc.get(IndexPerson.ID));
				}
				return ids;
			}

		} catch (Exception e) {
			log.warn("keyword=" + keyword + " 关键字搜索出错 ");
		}
		return new ArrayList<String>();

	}
}
